#ifndef __H_MVP_TRANSPORT_SHM_RECEIVER_H__
#define __H_MVP_TRANSPORT_SHM_RECEIVER_H__
#include <iostream>
#include <thread>
#include <memory>
#include "transport/receiver/receiver.h"
#include "transport/iox/iox_proxy.h"



namespace motovis {
namespace transport {

template <typename MessageT>
class ShmReceiver : public Receiver<MessageT> {
public:
    using MessagePtr = std::shared_ptr<MessageT>;
    using MessageListener = std::function<void(const MessagePtr& msg)>;


    ShmReceiver();
    ~ShmReceiver();

    void addListener(const std::string& channel_name, const MessageListener& msg_listener) override;
    void exec();
private:
    MessageListener listener_;
    std::shared_ptr<MessageT> msg_;
    std::string channel_name_;
    std::shared_ptr<std::thread> thread_;

};

template <typename MessageT>
ShmReceiver<MessageT>::ShmReceiver()
{
    IoxProxy::Instance();
}

template <typename MessageT>
ShmReceiver<MessageT>::~ShmReceiver()
{
    thread_->join();
}

template <typename MessageT>
void ShmReceiver<MessageT>::addListener(const std::string& channel_name, const MessageListener& msg_listener)
{
    msg_ = std::make_shared<MessageT>();
    channel_name_ = channel_name;
    listener_ = msg_listener;
    thread_ = std::make_shared<std::thread>(std::bind(&ShmReceiver::exec, this));
}

template <typename MessageT>
void ShmReceiver<MessageT>::exec()
{
    char name[100] = {0};
    strncpy(name, channel_name_.c_str(), channel_name_.size());
    iox::popo::UntypedSubscriber subscriber({"motovis", "transport", name});

    while(true)
    {
        subscriber
            .take()
            .and_then([&](const void* userPayload) {
                std::shared_ptr<MessageT> msg = std::make_shared<MessageT>(*static_cast<const MessageT*>(userPayload));
                listener_(msg);
                subscriber.release(userPayload);
            })
            .or_else([](auto& result) {
                if (result != iox::popo::ChunkReceiveResult::NO_CHUNK_AVAILABLE)
                {
                    //TODO : handle error
                }
            });

        std::this_thread::sleep_for(std::chrono::milliseconds(20));
    }
}


} // namespace transport
} // namespace motovis

#endif // __H_MVP_TRANSPORT_SHM_RECEIVER_H__